{{define "theme-default/home"}} {{template "common/header" .}} {{if ts .CustomCode}} {{.CustomCode|safe}} {{end}}
{{template "common/menu" .}}
<div class="nb-container">
  <div class="ui container">
    <div id="app">
      <div class="ui styled fluid accordion" v-for="group in groups">
        <div class="active title">
          <i class="dropdown icon"></i>@#(group.Tag!==''?group.Tag:'默认')#@
        </div>
        <div class="active content">
          <div class="ui four stackable status cards">
            <div v-for="server in group.data" :id="server.ID" class="ui card">
              <div class="content" v-if="server.Host" style="margin-top: 10px; padding-bottom: 5px">
                <div class="header">
                  <i :class="'flag-icon flag-icon-'+server.Host.CountryCode"></i>
                  <i v-if='server.Host.OS == "windows"' class="os-win10"></i>
                  <i v-if='server.Host.Platform == "darwin"' class="os-apple"></i>
                  <i v-if='server.Host.Platform == "suse"' class="os-opensuse"></i>
                  <i v-if='server.Host.Platform == "opensuse"' class="os-opensuse"></i>
                  <i :class="'os-'+server.Host.OS"></i>
                  <i :class="'os-'+server.Host.Platform"></i>
                  @#server.Name + (server.live?'':' [已离线]')#@
                  <i class="probe-primary-font info circle icon" style="height: 28px"></i>
                  <div class="ui content popup" style="">
                    系统：@#specialOS(server.Host.Platform)#@ <span
                      v-if='server.Host.OS!= "windows"'>@#server.Host.PlatformVersion#@ <span
                        v-if='!server.Host.Virtualization'>KVM</span></span> @#specialVir(server.Host.Virtualization)#@
                    [@#server.Host.Arch#@]<br />
                    CPU：@#clearString(server.Host.CPU)#@<br />
                    硬盘：@#formatByteSize(server.State.DiskUsed)#@ / @#formatByteSize(server.Host.DiskTotal)#@<br />
                    内存：@#formatByteSize(server.State.MemUsed)#@ / @#formatByteSize(server.Host.MemTotal)#@<br />
                    交换：@#formatByteSize(server.State.SwapUsed)#@ / @#formatByteSize(server.Host.SwapTotal)#@<br />
                    负载：@# toFixed2(server.State.Load1) #@ | @# toFixed2(server.State.Load5) #@ | @#
                    toFixed2(server.State.Load15) #@<br />
                    进程：@# server.State.ProcessCount #@ 个<br />
                    连接：TCP @# server.State.TcpConnCount #@ 个 | UDP @# server.State.UdpConnCount #@ 个 <br />
                    流量：<i
                      class="arrow alternate circle down outline icon s"></i>@#formatByteSize(server.State.NetInTransfer)#@
                    | <i
                      class="arrow alternate circle up outline icon s"></i>@#formatByteSize(server.State.NetOutTransfer)#@<br />
                    启动：@# formatTimestamp(server.Host.BootTime) #@<br />
                    活动：@# timeStamp(server.LastActive) #@<br />
                    版本：@#server.Host.Version#@<br />
                  </div>
                  <div class="ui divider" style="margin-bottom: 5px"></div>
                </div>
                <div class="description">
                  <div class="ui grid">
                    <div class="three wide column">CPU</div>
                    <div class="thirteen wide column">
                      <div :class="formatPercent(server.live,server.State.CPU, 100).class">
                        <div class="bar" :style="formatPercent(server.live,server.State.CPU, 100).style">
                          <small>@#formatPercent(server.live,server.State.CPU,100).percent#@%</small>
                        </div>
                      </div>
                    </div>
                    <div class="three wide column">内存</div>
                    <div class="thirteen wide column">
                      <div :class="formatPercent(server.live,server.State.MemUsed, server.Host.MemTotal).class">
                        <div class="bar"
                          :style="formatPercent(server.live,server.State.MemUsed, server.Host.MemTotal).style">
                          <small>@#parseInt(server.State?server.State.MemUsed/server.Host.MemTotal*100:0)#@%</small>
                        </div>
                      </div>
                    </div>
                    <div class="three wide column">交换</div>
                    <div class="thirteen wide column">
                      <div :class="formatPercent(server.live,server.State.SwapUsed, server.Host.SwapTotal).class">
                        <div class="bar"
                          :style="formatPercent(server.live,server.State.SwapUsed, server.Host.SwapTotal).style">
                          <small>@#parseInt(server.State?server.State.SwapUsed/server.Host.SwapTotal*100:0)#@%</small>
                        </div>
                      </div>
                    </div>
                    <div class="three wide column">网络</div>
                    <div class="thirteen wide column">
                      <i class="arrow alternate circle down outline icon"></i>
                      @#formatByteSize(server.State.NetInSpeed)#@/s |
                      <i class="arrow alternate circle up outline icon"></i>
                      @#formatByteSize(server.State.NetOutSpeed)#@/s
                    </div>
                    <div class="three wide column">硬盘</div>
                    <div class="thirteen wide column">
                      <div :class="formatPercent(server.live,server.State.DiskUsed, server.Host.DiskTotal).class">
                        <div class="bar"
                          :style="formatPercent(server.live,server.State.DiskUsed, server.Host.DiskTotal).style">
                          <small>@#parseInt(server.State?server.State.DiskUsed/server.Host.DiskTotal*100:0)#@%</small>
                        </div>
                      </div>
                    </div>
                    <div class="three wide column">在线</div>
                    <div class="thirteen wide column">
                      <i class="clock icon"></i>@#secondToDate(server.State.Uptime)#@
                    </div>
                  </div>
                </div>
              </div>
              <div class="content" v-else>
                <p>@#server.Name#@</p>
                <p>节点已离线</p>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
{{template "common/footer" .}}
<script>
  function specialOS(i) {
    if ((i.toString().toLowerCase().indexOf("windows")) != -1) {
      var i = i.replace("Microsoft ", "").replace("Datacenter", "").replace("Service Pack 1", "");
      return i;
    }
    i = i.toString().toLowerCase();
    switch (i) {
      case "ubuntu":
        return "Ubuntu";
        break;
      case "debian":
        return "Debian";
        break;
      case "centos":
        return "CentOS";
        break;
      case "darwin":
        return "MacOS";
        break;
      case "redhat":
        return "RedHat";
        break;
      case "archlinux":
        return "Archlinux";
        break;
      case "coreos":
        return "Coreos";
        break;
      case "deepin":
        return "Deepin";
        break;
      case "fedora":
        return "Fedora";
        break;
      case "alpine":
        return "Alpine";
        break;
      case "tux":
        return "Tux";
        break;
      case "linuxmint":
        return "LinuxMint";
        break;
      case "oracle":
        return "Oracle";
        break;
      case "slackware":
        return "SlackWare";
        break;
      case "raspbian":
        return "Raspbian";
        break;
      case "gentoo":
        return "GenToo";
        break;
      case "arch":
        return "Arch";
        break;
      case "amazon":
        return "Amazon";
        break;
      case "xenserver":
        return "XenServer";
        break;
      case "scientific":
        return "ScientificSL";
        break;
      case "rhel":
        return "Rhel";
        break;
      case "rawhide":
        return "RawHide";
        break;
      case "cloudlinux":
        return "CloudLinux";
        break;
      case "ibm_powerkvm":
        return "IBM";
        break;
      case "almalinux":
        return "Almalinux";
        break;
      case "suse":
        return "Suse";
        break;
      case "opensuse":
        return "OpenSuse";
        break;
      case "opensuse-leap":
        return "OpenSuse";
        break;
      case "opensuse-tumbleweed":
        return "OpenSuse";
        break;
      case "opensuse-tumbleweed-kubic":
        return "OpenSuse";
        break;
      case "sles":
        return "Sles";
        break;
      case "sled":
        return "Sled";
        break;
      case "caasp":
        return "Caasp";
        break;
      case "exherbo":
        return "ExherBo";
        break;
      case "solus":
        return "Solus";
        break;
      default:
        return i;
    }
  }
  function specialVir(i) {
    i = i.toString().toLowerCase();
    switch (i) {
      case "kvm":
        return "KVM";
        break;
      case "openvz":
        return "OpenVZ";
        break;
      case "lxc":
        return "LXC";
        break;
      case "xen":
        return "Xen";
        break;
      case "vbox":
        return "VBox";
        break;
      case "rkt":
        return "RKT";
        break;
      case "docker":
        return "Docker";
        break;
      case "vmware":
        return "VMware";
        break;
      case "linux-vserver":
        return "VServer";
        break;
      default:
        return i;
    }
  }
  function clearString(i) {
    if (i != null && i != "") {
      i = i.toString();
      return i.replace(/(\r|\n|\"|\]|\[)/ig, "").replace(/(\\)/ig, "");
    }
    return i;
  }

  Date.prototype.format = function (format) {
    var date = {
      "M+": this.getMonth() + 1,
      "d+": this.getDate(),
      "H+": this.getHours(),
      "m+": this.getMinutes(),
      "s+": this.getSeconds(),
      "q+": Math.floor((this.getMonth() + 3) / 3),
      "S+": this.getMilliseconds()
    };
    if (/(y+)/i.test(format)) {
      format = format.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length));
    }
    for (var k in date) {
      if (new RegExp("(" + k + ")").test(format)) {
        format = format.replace(RegExp.$1, RegExp.$1.length == 1
          ? date[k] : ("00" + date[k]).substr(("" + date[k]).length));
      }
    }
    return format;
  }
  const initData = JSON.parse('{{.Servers}}').servers;
  var statusCards = new Vue({
    el: '#app',
    delimiters: ['@#', '#@'],
    data: {
      data: initData,
      groups: [],
      cache: [],
    },
    created() {
      this.group()
    },
    mounted() {
      $('.probe-primary-font.info.icon').popup({
        popup: '.ui.content.popup',
        exclusive: true,
      });
    },
    methods: {
      toFixed2(f) {
        return f.toFixed(2)
      },
      group() {
        this.groups = groupingData(this.data, "Tag")
      },
      formatPercent(live, used, total) {
        const percent = live ? (parseInt(used / total * 100) || 0) : -1
        if (!this.cache[percent]) {
          this.cache[percent] = {
            class: {
              ui: true,
              progress: true,
            },
            style: {
              'transition-duration': '300ms',
              'min-width': 'unset',
              width: percent + '% !important',
            },
            percent,
          }
          if (percent < 0) {
            this.cache[percent].style['background-color'] = 'slategray'
            this.cache[percent].class.offline = true
          } else if (percent < 71) {
            this.cache[percent].style['background-color'] = 'rgb(76,175,80)'
            this.cache[percent].class.fine = true
          } else if (percent < 91) {
            this.cache[percent].style['background-color'] = '#ff9800'
            this.cache[percent].class.warning = true
          } else {
            this.cache[percent].style['background-color'] = '#f44336'
            this.cache[percent].class.error = true
          }
        }
        return this.cache[percent]
      },
      secondToDate(s) {
        var d = Math.floor(s / 3600 / 24);
        if (d > 0) {
          return d + "天"
        }
        var h = Math.floor(s / 3600 % 24);
        var m = Math.floor(s / 60 % 60);
        var s = Math.floor(s % 60);
        return h + ":" + ("0" + m).slice(-2) + ":" + ("0" + s).slice(-2);
      },
      formatTimestamp(t) {
        return new Date(t * 1000).format('yyyy年MM月dd日 HH:mm:ss')
      },
      timeStamp(t) {
        return new Date(t).format('yyyy年MM月dd日 HH:mm:ss')
      },
      formatByteSize(bs) {
        const x = readableBytes(bs)
        return x != "NaN undefined" ? x : '0B'
      }
    }
  })

  function groupingData(data, filed) {
    let map = {};
    let dest = [];
    data.forEach(item => {
      if (!map[item[filed]]) {
        dest.push({
          [filed]: item[filed],
          data: [item]
        });
        map[item[filed]] = item;
      } else {
        dest.forEach(dItem => {
          if (dItem[filed] == item[filed]) {
            dItem.data.push(item);
          }
        });
      }
    })
    return dest;
  }

  const wsProtocol = window.location.protocol == "https:" ? "wss" : "ws"
  const ws = new WebSocket(wsProtocol + '://' + window.location.host + '/ws');
  ws.onmessage = function (evt) {
    const oldServers = statusCards.servers
    const data = JSON.parse(evt.data)
    statusCards.servers = data.servers
    for (let i = 0; i < statusCards.servers.length; i++) {
      const ns = statusCards.servers[i];
      if (!ns.Host) ns.live = false
      else {
        const lastActive = new Date(ns.LastActive).getTime()
        if (data.now - lastActive > 10 * 1000) {
          ns.live = false
        } else {
          ns.live = true
        }
      }
    }
    statusCards.groups = groupingData(statusCards.servers, "Tag")
  }
  $('.ui.accordion')
    .accordion({ "exclusive": false });
</script>
<script>
  var statusList = document.getElementsByTagName('small')
  for (i = 0; i < statusList.length; i++) {
    if (statusList[i].innerText == 'NaN%') {
      statusList[i].innerText = '无'
    }
  }    
</script>
{{end}}